﻿//---------------------------------------------------------------------------
// sgl.cpp
// Empty implementation of the SGL (Simple Graphics Library)
// Date:  2011/11/1
// Author: Lenka Saidlová, Václav Strnad
// aktu8ln9 verye 
//---------------------------------------------------------------------------

#include "sgl.h"
#include "ContextManage.h"
#include <cmath>
#include <algorithm>
#include "limits.h"
#include "float.h"
#include "MyColor.h"
#include "MyMaterial.h"
#include "MyMatrix.h"
#include "MyPhong.h"
#include "MyPointLight.h"
#include "MyPrimitive.h"
#include "MyRay.h"
#include "MySphere.h"
#include "MyTriangle.h"
#include "MyVector3.h"

#ifndef M_PI
#define M_PI       3.14159265358979323846
#endif


/// Current error code.
static sglEErrorCode _libStatus = SGL_NO_ERROR;
static ContextManage * contextManage;

static inline void setErrCode(sglEErrorCode c) 
{
  if(_libStatus==SGL_NO_ERROR)
    _libStatus = c;
}

//---------------------------------------------------------------------------
// sglGetError()
//---------------------------------------------------------------------------
sglEErrorCode sglGetError(void) 
{
  sglEErrorCode ret = _libStatus;
  _libStatus = SGL_NO_ERROR;
  return ret;
}

//---------------------------------------------------------------------------
// sglGetErrorString()
//---------------------------------------------------------------------------
const char* sglGetErrorString(sglEErrorCode error)
{
  static const char *errStrigTable[] = 
  {
      "Operation succeeded",
      "Invalid argument(s) to a call",
      "Invalid enumeration argument(s) to a call",
      "Invalid call",
      "Quota of internal resources exceeded",
      "Internal library error",
      "Matrix stack overflow",
      "Matrix stack underflow",
      "Insufficient memory to finish the requested operation"
  };

  if((int)error<(int)SGL_NO_ERROR || (int)error>(int)SGL_OUT_OF_MEMORY ) {
    return "Invalid value passed to sglGetErrorString()"; 
  }

  return errStrigTable[(int)error];
}

//---------------------------------------------------------------------------
// Initialization functions
//---------------------------------------------------------------------------
//init context manager
void sglInit(void) {

	contextManage = new ContextManage();
}

void sglFinish(void) {}
//cretae new context, return id
//max count is 32
int sglCreateContext(int width, int height) {
	
	if(contextManage->contextCount > 31){
	
		setErrCode(SGL_OUT_OF_RESOURCES);
		return -1;
	}

	int id = contextManage->createContext(width,height);
	contextManage->contextCount++;

	return id;
}

void sglDestroyContext(int id) {}
//set actual context
void sglSetContext(int id) {

	if(id >= contextManage->contextCount){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
		
	}
	else{
		contextManage->setContext(id);
	}
}

int sglGetContext(void) {return 0;}

float *sglGetColorBufferPointer(void) {
	
	return contextManage->cc->getColorBufferPointer();
}

//---------------------------------------------------------------------------
// Drawing functions
//---------------------------------------------------------------------------
//set currentColor
void sglClearColor (float r, float g, float b, float alpha) {

	if(contextManage->contextCount == 0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}
	contextManage->cc->currentColor.r = r;
	contextManage->cc->currentColor.g = g;
	contextManage->cc->currentColor.b = b;
}
//clear color buffer or set z-buffer to infinity
void sglClear(unsigned what) {

	if(contextManage->cc->drawing || contextManage->contextCount==0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if (what == SGL_COLOR_BUFFER_BIT){
	
		for(int i=0; i< contextManage->cc->width*contextManage->cc->height; i++){
		
			contextManage->cc->colorBuffer[i].r = 0;
			contextManage->cc->colorBuffer[i].g = 0;
			contextManage->cc->colorBuffer[i].b = 0;
		}
	}

	else if(what == SGL_DEPTH_BUFFER_BIT){
	
		for(int i=0; i< contextManage->cc->width*contextManage->cc->height; i++){
		
			contextManage->cc->z_buffer[i] = FLT_MAX;
			
		}
	}
	else{
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}
}
//set element type
//clear vectorBuffer
//set parameter drawing as true
void sglBegin(sglEElementType mode) {

	

	if(mode == SGL_POINTS || mode == SGL_LINES || mode == SGL_LINE_STRIP || mode == SGL_LINE_LOOP || mode == SGL_TRIANGLES || mode == SGL_POLYGON || mode == SGL_AREA_LIGHT){
	
	contextManage->cc->elementType = mode;
	contextManage->cc->vectorBuffer.clear();
	contextManage->cc->drawing = true;
	}

	else{
	
		setErrCode(SGL_INVALID_ENUM);
	}

}

//write pixel to color buffer
// if depth test is enabled -> each vertex is compared to z-buffer
void writePixel(int index, float z){

	if (index >= 0 && index <= (contextManage->cc->width * contextManage->cc->height)) {
		if(contextManage->cc->depth_test){
		
			if (contextManage->cc->z_buffer[index] > z) {
				contextManage->cc->z_buffer[index] = z;
				contextManage->cc->colorBuffer[index] = contextManage->cc->currentColor;
			}
		}
		else{
				contextManage->cc->colorBuffer[index] = contextManage->cc->currentColor;
		}
	} else {
		//printf("Out of bound buffer in writePixel().\n");
		return;
	}
}

//help function to drawing line
void drawLine(int x1, int y1, float z1, int x2, int y2, float z2){

	int startX = x1;
	int startY = y1;

	int endX = x2;
	int endY = y2;

	float startZ = z1;
	float endZ = z2;

	//if false, switch 
	if(startX > endX){
		
		int help = startX;
		startX = endX;
		endX = help;

		help = startY;
		startY = endY;
		endY = help;

		float help2 = startZ;
		startZ = endZ;
		endZ = help2;
	}


	int c0,c1,p; 
	float width = (float) abs(endX - startX);
	float height = (float) abs(endY - startY);

	//find out k and divide to 4 cases
	float k = (float)(endY - startY)/(endX - startX);
	float z_step;
			
	// first case
	if (k >= 0 && k <= 1){
	
		c0 = 2 * (endY - startY);
		c1 = c0 - 2 * (endX - startX);
		p = c0 - (endX - startX);
		z_step = (endZ-startZ)/(float)width;
		
		writePixel(startX+startY*(contextManage->cc->width),startZ);
		
		startZ += z_step;		

		for (int i = startX + 1; i <= endX; i++) {
			
			if (p < 0) {
				p += c0;
			}
			else {
				p += c1;
				startY++;
			}
	
			writePixel(i+startY*(contextManage->cc->width),startZ);
			
			startZ += z_step;
						
		}
	}

	//second case
	if (k > 1 || startX == endX){
	
		c0 = 2 * (endX - startX);
		c1 = c0 - 2 * (endY - startY);
		p = c0 - (endY - startY);
		z_step = (endZ-startZ)/(float)height;

		writePixel(startX+startY*(contextManage->cc->width),startZ);
		startZ += z_step;

		for (int i = startY + 1; i <= endY; i++) {
			if (p < 0) {
				p += c0;
			}
			else {
				p += c1;
				startX++;
			}
			
			writePixel(startX+i*(contextManage->cc->width),startZ);
			
			startZ += z_step;
					
			}
	}
	//third case
	if (k < 0 && k >= -1){
	
		c0 = 2 * (startY - endY);
		c1 = c0 - 2 * (endX - startX);
		p = c0 - (endX - startX);
		z_step = (endZ-startZ)/(float)width;

		writePixel(startX+startY*(contextManage->cc->width),startZ);
		startZ += z_step;
				
		for (int i = startX + 1; i <= endX; i++) {
			if (p < 0) {
				p += c0;
			}
			else {
				p += c1;
				startY--;
			}
			
			writePixel(i+startY*(contextManage->cc->width),startZ);
			
			startZ += z_step;
							}
	}
			
	//fourth case
	if (k < -1){
	
		c0 = 2 * (endX - startX);
		c1 = c0 - 2 * (startY - endY);
		p = c0 - (startY - endY);
		z_step = abs(endZ-startZ)/(float)height;

		writePixel(startX+startY*(contextManage->cc->width),startZ);
		startZ += z_step;
			
		for (int i = startY - 1; i >= endY; i--) {
			if (p < 0) {
				p += c0;
			}
			else {
				p += c1;
				startX++;
			}
			
			writePixel(startX+i*(contextManage->cc->width),startZ);
			
			startZ += z_step;
		}
	}
	
}

bool compareMyVector3(MyVector3 i, MyVector3 j) {
        return i.x<j.x;
}

//SGL_POINTS - writes pixels
//SGL_LINES, LOOP, STRIP - calls drawLine 
//set drawing to false
void sglEnd(void) {

	if(contextManage->cc->sceneDefiniton){
	
		contextManage->cc->end();
		return;
	}
	
	if(contextManage->cc->elementType == SGL_POINTS){
	
		if(contextManage->cc->pointSize >1){
			for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size(); i++){
				int x = (int) (contextManage->cc->vectorBuffer.at(i).x - ((contextManage->cc->pointSize / 2) - 1));			
				int y = (int) (contextManage->cc->vectorBuffer.at(i).y - ((contextManage->cc->pointSize / 2) - 1));
				for(int row = 0; row < contextManage->cc->pointSize; row++) { //radky
					for(int col = 0; col < contextManage->cc->pointSize; col++) { //sloupce
						
						writePixel((x + col)+(y + row)*(contextManage->cc->width),contextManage->cc->vectorBuffer.at(i).z);
						
					}
				}
			}
		} else{
			for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size(); i++){
				int x = (int) (contextManage->cc->vectorBuffer.at(i).x);			
				int y = (int) (contextManage->cc->vectorBuffer.at(i).y);
			
				writePixel(x+y*(contextManage->cc->width),contextManage->cc->vectorBuffer.at(i).z);
											
			}
		}		
	}

	if(contextManage->cc->elementType == SGL_LINES){

		//2 points for every line
		for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size(); i=i+2){
			
			drawLine((int) contextManage->cc->vectorBuffer.at(i).x, (int) contextManage->cc->vectorBuffer.at(i).y, contextManage->cc->vectorBuffer.at(i).z,
					 (int) contextManage->cc->vectorBuffer.at(i+1).x, (int) contextManage->cc->vectorBuffer.at(i+1).y, contextManage->cc->vectorBuffer.at(i+1).z);
		
		}
	}
		
	if(contextManage->cc->elementType == SGL_LINE_STRIP){

			for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size()-1; i=i+1){
	
				drawLine((int) contextManage->cc->vectorBuffer.at(i).x, (int) contextManage->cc->vectorBuffer.at(i).y,contextManage->cc->vectorBuffer.at(i).z,
						 (int) contextManage->cc->vectorBuffer.at(i+1).x, (int) contextManage->cc->vectorBuffer.at(i+1).y,contextManage->cc->vectorBuffer.at(i+1).z);
			}
	}
		

	if(contextManage->cc->elementType == SGL_LINE_LOOP){

			//the first point set also as the last
		contextManage->cc->vectorBuffer.push_back(contextManage->cc->vectorBuffer.at(0));
			
		for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size()-1; i=i+1){
	
			drawLine((int) contextManage->cc->vectorBuffer.at(i).x, (int) contextManage->cc->vectorBuffer.at(i).y,contextManage->cc->vectorBuffer.at(i).z,
					 (int) contextManage->cc->vectorBuffer.at(i+1).x, (int) contextManage->cc->vectorBuffer.at(i+1).y,contextManage->cc->vectorBuffer.at(i+1).z);
		}
	}

	 if(contextManage->cc->elementType == SGL_POLYGON){
                
               if (contextManage->cc->areaMode == SGL_FILL) {
                        std::vector<MyVector3> fill;
                        MyVector3 nextPoint;
                        std::vector<int> indexTopPoints;
                        std::vector<MyVector3> fillRanges;
						int maxY = INT_MIN;
						int minY = INT_MAX;
                        float xChange, zChange;
                        // uloí hrany
                        for (unsigned int i = 0; i < contextManage->cc->vectorBuffer.size(); i++) {
                                int prevIndex = (i-1 + contextManage->cc->vectorBuffer.size()) % contextManage->cc->vectorBuffer.size();
                                int nextIndex = (i+1 + contextManage->cc->vectorBuffer.size()) % contextManage->cc->vectorBuffer.size();
                                if (contextManage->cc->vectorBuffer.at(i).y > contextManage->cc->vectorBuffer.at(prevIndex).y) {
                                        fillRanges.push_back(contextManage->cc->vectorBuffer.at(i));
                                        fillRanges.push_back(contextManage->cc->vectorBuffer.at(prevIndex));
                                }
                                if (contextManage->cc->vectorBuffer.at(i).y > contextManage->cc->vectorBuffer.at(nextIndex).y) {
                                        fillRanges.push_back(contextManage->cc->vectorBuffer.at(i));
                                        fillRanges.push_back(contextManage->cc->vectorBuffer.at(nextIndex));
                                }
                        }
                        for (unsigned int i = 0; i < contextManage->cc->vectorBuffer.size(); i++) {
                                if (contextManage->cc->vectorBuffer.at(i).y > maxY) {
                                        maxY = (int) contextManage->cc->vectorBuffer.at(i).y;
                                }
                                if (contextManage->cc->vectorBuffer.at(i).y < minY) {
                                        minY = (int) contextManage->cc->vectorBuffer.at(i).y;
                                }
                        }
                        //prochází po øádcích polygonu
                        for (int i = maxY; i >= minY; i--) {
                                for (unsigned int j = 0; j < fillRanges.size(); j = j+2) {
                                        if (fillRanges.at(j).y >= i && fillRanges.at(j+1).y < i) {
                                                xChange = (fillRanges.at(j).x - fillRanges.at(j+1).x) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
												zChange = (fillRanges.at(j).z - fillRanges.at(j+1).z) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
                                                nextPoint.x = (fillRanges.at(j).x + xChange*(i-fillRanges.at(j).y));
                                                nextPoint.y = (float) i;
                                                nextPoint.z = fillRanges.at(j).z + zChange*(i-fillRanges.at(j).y);
                                                fill.push_back(nextPoint);
                                        }
                                }
                                std::sort(fill.begin(), fill.end(), compareMyVector3);
                                for (unsigned int j = 0; j < fill.size(); j = j+2) {
                                        drawLine((int) fill.at(j).x, (int) fill.at(j).y, fill.at(j).z, (int) fill.at(j+1).x, (int) fill.at(j+1).y, fill.at(j+1).z);
                                }
                                fill.clear();
                        }
                } else if (contextManage->cc->areaMode == SGL_LINE) {
					//printf("kreslim\n");
                        contextManage->cc->vectorBuffer.push_back(contextManage->cc->vectorBuffer.at(0));
                        for(unsigned int i = 0; i < contextManage->cc->vectorBuffer.size()-1; i=i+1){
						       drawLine((int) contextManage->cc->vectorBuffer.at(i).x, (int) contextManage->cc->vectorBuffer.at(i).y,contextManage->cc->vectorBuffer.at(i).z,
                                         (int) contextManage->cc->vectorBuffer.at(i+1).x, (int) contextManage->cc->vectorBuffer.at(i+1).y,contextManage->cc->vectorBuffer.at(i+1).z);
                        }
                } else if (contextManage->cc->areaMode == SGL_POINT) {
                        int x = 0;
                        int y = 0;
                        for (unsigned int i = 1; i < contextManage->cc->vectorBuffer.size(); i++) {
                                x = (int) (contextManage->cc->vectorBuffer.at(i).x);                    
                                y = (int) (contextManage->cc->vectorBuffer.at(i).y);
                                writePixel(x + y*(contextManage->cc->width),contextManage->cc->vectorBuffer.at(i).z);
                        }
                }
        }

	contextManage->cc->drawing = false;
		
}


//---------------------------------------------------------------------------
// Set vertices and push them to buffer
//---------------------------------------------------------------------------

//help function to aplicate all transformations
MyVector3 setVertex(float x, float y, float z, float w){

	MyVector3 mv;
	mv.x = x * contextManage->cc->aplicMatrix[0] + y * contextManage->cc->aplicMatrix[1] + z * contextManage->cc->aplicMatrix[2] + w * contextManage->cc->aplicMatrix[3];
	mv.y = x * contextManage->cc->aplicMatrix[4] + y * contextManage->cc->aplicMatrix[5] + z * contextManage->cc->aplicMatrix[6] + w * contextManage->cc->aplicMatrix[7];
	mv.z = x * contextManage->cc->aplicMatrix[8] + y * contextManage->cc->aplicMatrix[9] + z * contextManage->cc->aplicMatrix[10] + w *contextManage->cc->aplicMatrix[11];
	mv.w = x * contextManage->cc->aplicMatrix[12] + y * contextManage->cc->aplicMatrix[13] + z * contextManage->cc->aplicMatrix[14] + w * contextManage->cc->aplicMatrix[15];

	mv.x = mv.x / mv.w;
	mv.y = mv.y / mv.w;
	mv.z = mv.z / mv.w;
	mv.w = 1;
	
	mv.x = (mv.x+1) * (contextManage->cc->viewportWidth/2)+contextManage->cc->viewportX;
	mv.y = (mv.y+1) * (contextManage->cc->viewportHeight/2)+contextManage->cc->viewportY;
	
	return mv;
}

void sglVertex4f(float x, float y, float z, float w) {

	contextManage->cc->clearAplicMatrix();
	contextManage->cc->setAplicMatrix();
	MyVector3 mv = setVertex(x,y,z,w);
	contextManage->cc->vectorBuffer.push_back(mv);

}

void sglVertex3f(float x, float y, float z) {

	MyVector3 mv;

	if(!contextManage->cc->sceneDefiniton){
		contextManage->cc->clearAplicMatrix();
		contextManage->cc->setAplicMatrix();
		mv = setVertex(x,y,z,1);
	}
	else{
		mv.x = x;
		mv.y = y;
		mv.z = z;
		
	}
	
	contextManage->cc->vectorBuffer.push_back(mv);
}

void sglVertex2f(float x, float y) {
	
	contextManage->cc->clearAplicMatrix();
	contextManage->cc->setAplicMatrix();
	MyVector3 mv = setVertex(x,y,0,1);
	contextManage->cc->vectorBuffer.push_back(mv);
}
//help function to filling circle
void drawCirclePoints(float pointL, float pointR, float z) {
	if (contextManage->cc->areaMode == SGL_FILL) {
		for (int i = (int) pointL; i <= (int) pointR; i++){
			writePixel(i,z);
			
		}
	} else if (contextManage->cc->areaMode == SGL_LINE) {
		writePixel((int) pointL,z);
		writePixel((int) pointR,z);
		
	}
}
//---------------------------------------------------------------------------
// Drawing circle, ellipse and arc
//---------------------------------------------------------------------------

void sglCircle(float x, float y, float z, float radius) {
	
	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(radius <= 0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}

	contextManage->cc->clearAplicMatrix();
	contextManage->cc->setAplicMatrix();
	
	
	float * helpMatrix = new float[16];
	float * helpMatrix2 = new float[16];

	for(int i=0; i<16; i++){
		helpMatrix[i] = 0;
		helpMatrix2[i] = 0;
	}

	helpMatrix[0] = contextManage->cc->viewportWidth/2.0f;
	helpMatrix[3] = contextManage->cc->viewportWidth/2.0f + contextManage->cc->viewportX;
	helpMatrix[5] = contextManage->cc->viewportHeight/2.0f;
	helpMatrix[7] = contextManage->cc->viewportHeight/2.0f + contextManage->cc->viewportY;
	helpMatrix[10] = 1;
	helpMatrix[15] = 1;

	
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			for (int inner = 0; inner < 4; inner++) {
				helpMatrix2[4 * i + j] += contextManage->cc->aplicMatrix[4 * inner + j] * helpMatrix[4 * i + inner];
			}
		}
	}
	
	radius = radius * sqrt((helpMatrix2[0] * helpMatrix2[5]) - (helpMatrix2[4] * helpMatrix2[1]));
	
	MyVector3 mv = setVertex(x,y,z,1);
	
	x = mv.x;
	y = mv.y;
	z = mv.z;

	int circleX = 0;
	int circleY = (int)(radius+0.5f);
	int p = 3 - 2 * (int)radius;
		
	while (circleX < circleY) {
		
		drawCirclePoints((contextManage->cc->width * (y + circleY) + x - circleX), (contextManage->cc->width * (y + circleY) + x + circleX),z);
		drawCirclePoints((contextManage->cc->width * (y + circleX) + x - circleY), (contextManage->cc->width * (y + circleX) + x + circleY),z);
		drawCirclePoints((contextManage->cc->width * (y - circleX) + x - circleY), (contextManage->cc->width * (y - circleX) + x + circleY),z);
		drawCirclePoints((contextManage->cc->width * (y - circleY) + x - circleX), (contextManage->cc->width * (y - circleY) + x + circleX),z);

		if (p <0){
			p = p + 4 * circleX + 6;
		}
		else {
			p = p + 4 * (circleX - circleY) + 10;
			circleY = circleY - 1;
		}
		circleX = circleX + 1;
	}
	if (circleX == circleY) {
			
		drawCirclePoints((contextManage->cc->width * (y + circleY) + x - circleX), (contextManage->cc->width * (y + circleY) + x + circleX),z);
		drawCirclePoints((contextManage->cc->width * (y + circleX) + x - circleY), (contextManage->cc->width * (y + circleX) + x + circleY),z);
		drawCirclePoints((contextManage->cc->width * (y - circleX) + x - circleY), (contextManage->cc->width * (y - circleX) + x + circleY),z);
		drawCirclePoints((contextManage->cc->width * (y - circleY) + x - circleX), (contextManage->cc->width * (y - circleY) + x + circleX),z);
	}
}


//drawing ellipse
void sglEllipse(float x, float y, float z, float a, float b) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(a<=0 || b<=0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}

	std::vector<MyVector3> ellipse;
    contextManage->cc->clearAplicMatrix();
	contextManage->cc->setAplicMatrix();

	float step = (float)(2 * M_PI) / 40;
        
    for (float fi = 0; fi < 2 * M_PI; fi += step) {
            MyVector3 point = setVertex(x + a * cos(fi),y + b * sin(fi),z,1);
            ellipse.push_back(point);
    }
        
    if (contextManage->cc->areaMode == SGL_FILL) {
        std::vector<MyVector3> fill;
        MyVector3 nextPoint;
        std::vector<int> indexTopPoints;
        std::vector<MyVector3> fillRanges;
		int maxY = INT_MIN;
		int minY = INT_MAX;
        float xChange1, zChange;
        // uloí hrany
        
        for (unsigned int i = 0; i < ellipse.size(); i++) {
            int prevIndex = (i-1 + ellipse.size()) % ellipse.size();
            int nextIndex = (i+1 + ellipse.size()) % ellipse.size();
            if (ellipse.at(i).y > ellipse.at(prevIndex).y) {
				fillRanges.push_back(ellipse.at(i));
				fillRanges.push_back(ellipse.at(prevIndex));
            }
            if (ellipse.at(i).y > ellipse.at(nextIndex).y) {
                fillRanges.push_back(ellipse.at(i));
                fillRanges.push_back(ellipse.at(nextIndex));
            }
        }
        
        for (unsigned int i = 0; i < ellipse.size(); i++) {
            if (ellipse.at(i).y > maxY) {
				maxY = (int) ellipse.at(i).y;
            }
            if (ellipse.at(i).y < minY) {
                minY = (int) ellipse.at(i).y;
            }
        }
        //prochází po øádcích polygonu
        for (int i = maxY; i > minY; i--) {
            for (unsigned int j = 0; j < fillRanges.size(); j = j+2) {
                if (fillRanges.at(j).y >= i && fillRanges.at(j+1).y < i) {
                    xChange1 = (fillRanges.at(j).x - fillRanges.at(j+1).x) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
					zChange = (fillRanges.at(j).z - fillRanges.at(j+1).z) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
                    nextPoint.x = fillRanges.at(j).x + xChange1*(i-fillRanges.at(j).y);
                    nextPoint.y = (float)i;
                    nextPoint.z = fillRanges.at(j).z + zChange*(i-fillRanges.at(j).y);
                    fill.push_back(nextPoint);
                }
            }
            std::sort(fill.begin(), fill.end(), compareMyVector3);
            for (unsigned int j = 0; j < fill.size(); j = j+2) {
                drawLine((int) fill.at(j).x, (int) fill.at(j).y, fill.at(j).z, (int) fill.at(j+1).x, (int) fill.at(j+1).y, fill.at(j+1).z);
            }
            fill.clear();
                
        }
    } else if (contextManage->cc->areaMode == SGL_LINE) {   
        ellipse.push_back(ellipse.at(0));
        for(unsigned int i = 0; i < ellipse.size()-1; i++){
            drawLine((int) ellipse.at(i).x, (int) ellipse.at(i).y, ellipse.at(i).z, 
					 (int) ellipse.at(i+1).x, (int) ellipse.at(i+1).y, ellipse.at(i+1).z);
        }
    } else if (contextManage->cc->areaMode == SGL_POINT) {
        for ( unsigned int i = 1; i < ellipse.size(); i++) {
			writePixel((int) (ellipse.at(i).x + ellipse.at(i).y*(contextManage->cc->width)), ellipse.at(i).z);
        }
    }
	
}
//drawing arc
void sglArc(float x, float y, float z, float radius, float from, float to) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(radius <= 0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}
	float step = ((to - from) / 40);
	
	std::vector<MyVector3> arc;
	MyVector3 point;
	contextManage->cc->clearAplicMatrix();
	contextManage->cc->setAplicMatrix();

	if (from < to) {
		for (float fi = from; fi < to; fi += step) {
			point = setVertex(x + radius * cos(fi),y + radius * sin(fi),z,1);
			arc.push_back(point);
		}
		point = setVertex(x + radius * cos(to),y + radius * sin(to),z,1);
		arc.push_back(point);
	}
	    
    if (contextManage->cc->areaMode == SGL_FILL) {
        std::vector<MyVector3> fill;
        MyVector3 nextPoint;
        std::vector<int> indexTopPoints;
        std::vector<MyVector3> fillRanges;
		int maxY = INT_MIN;
		int minY = INT_MAX;
        float xChange1, zChange;

		// přidání středového body pro uzavření vyplňování
		point = setVertex(x,y,z,1);
		
		arc.push_back(point);
		
		// uloží hrany        
        for (unsigned int i = 0; i < arc.size(); i++) {
            int prevIndex = (i-1 + arc.size()) % arc.size();
            int nextIndex = (i+1 + arc.size()) % arc.size();
            if (arc.at(i).y > arc.at(prevIndex).y) {
				fillRanges.push_back(arc.at(i));
				fillRanges.push_back(arc.at(prevIndex));
            }
            if (arc.at(i).y > arc.at(nextIndex).y) {
                fillRanges.push_back(arc.at(i));
                fillRanges.push_back(arc.at(nextIndex));
            }
        }
        
        for (unsigned int i = 0; i < arc.size(); i++) {
            if (arc.at(i).y > maxY) {
				maxY = (int) arc.at(i).y;
            }
            if (arc.at(i).y < minY) {
                minY = (int) arc.at(i).y;
            }
        }
        //prochází po øádcích polygonu
        for (int i = maxY; i > minY; i--) {
            for (unsigned int j = 0; j < fillRanges.size(); j = j+2) {
                if (fillRanges.at(j).y >= i && fillRanges.at(j+1).y < i) {
                    xChange1 = (fillRanges.at(j).x - fillRanges.at(j+1).x) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
					zChange = (fillRanges.at(j).z - fillRanges.at(j+1).z) / (fillRanges.at(j).y - fillRanges.at(j+1).y);
                    nextPoint.x = fillRanges.at(j).x + xChange1*(i-fillRanges.at(j).y);
                    nextPoint.y = (float)i;
                    nextPoint.z = fillRanges.at(j).z + zChange*(i-fillRanges.at(j).y);
                    fill.push_back(nextPoint);
                }
            }
            std::sort(fill.begin(), fill.end(), compareMyVector3);
            for (unsigned int j = 0; j < fill.size(); j = j+2) {
                drawLine((int) fill.at(j).x, (int) fill.at(j).y, fill.at(j).z, (int) fill.at(j+1).x, (int) fill.at(j+1).y, fill.at(j+1).z);
            }
            fill.clear();
                
        }
    } else if (contextManage->cc->areaMode == SGL_LINE) {   
        for(unsigned int i = 0; i < arc.size()-1; i++){
            drawLine((int) arc.at(i).x, (int) arc.at(i).y, arc.at(i).z, 
					 (int) arc.at(i+1).x, (int) arc.at(i+1).y, arc.at(i+1).z);
        }
    } else if (contextManage->cc->areaMode == SGL_POINT) {
        for (unsigned int i = 1; i < arc.size(); i++) {
            writePixel((int) (arc.at(i).x + arc.at(i).y*(contextManage->cc->width)), arc.at(i).z);
        }
    }
	
}

//---------------------------------------------------------------------------
// Transform functions
//---------------------------------------------------------------------------

//set matrix mode
void sglMatrixMode( sglEMatrixMode mode ) {

	if(contextManage->contextCount == 0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(mode == SGL_MODELVIEW || mode == SGL_PROJECTION){
	
		contextManage->cc->matrixMode = mode;
	
	}
	else{
	
		setErrCode(SGL_INVALID_ENUM);
		return;
	}
	
}

//save modelViewMatrix to array
//DODELAT PRO PROJEKCNI MATICI
void sglPushMatrix(void) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(contextManage->cc->matrixMode == SGL_MODELVIEW){
		if (contextManage->cc->modelViewStackSize < 31) {
			for (int i = 0; i < 16; i++){
				contextManage->cc->modelViewStack[contextManage->cc->modelViewStackSize * 16 + i] = contextManage->cc->modelViewMatrix[i];
			}
			contextManage->cc->modelViewStackSize += 1;
		}else {

			setErrCode(SGL_STACK_OVERFLOW);
			return;
		
		};
	} 

}
//return modelViewMatrix from array
//DODELAT PRO PROJEKCNI MATICI
void sglPopMatrix(void) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(contextManage->cc->matrixMode == SGL_MODELVIEW){
		if (contextManage->cc->modelViewStackSize > 0) {
			for (int i = 0; i < 16; i++){
				contextManage->cc->modelViewMatrix[i] = contextManage->cc->modelViewStack[(contextManage->cc->modelViewStackSize-1) * 16 + i];
			}
			contextManage->cc->modelViewStackSize -= 1;
		}else {

			setErrCode(SGL_STACK_UNDERFLOW);
			return;
		
		};
	}
}
//set actual matrix to "jednotkova"
void sglLoadIdentity(void) {
/*
	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}
*/
	if(contextManage->cc->matrixMode == SGL_MODELVIEW){

		contextManage->cc->modelViewMatrix = MyMatrix::getIdentityMatrix();
	}

	if(contextManage->cc->matrixMode == SGL_PROJECTION){

		contextManage->cc->projectionMatrix = MyMatrix::getIdentityMatrix();
	}
}
// set actual matrix
void sglLoadMatrix(const float *matrix) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(contextManage->cc->matrixMode == SGL_MODELVIEW){
	
		contextManage->cc->modelViewMatrix[0]=matrix[0];
		contextManage->cc->modelViewMatrix[1]=matrix[4];
		contextManage->cc->modelViewMatrix[2]=matrix[8];
		contextManage->cc->modelViewMatrix[3]=matrix[12];
		contextManage->cc->modelViewMatrix[4]=matrix[1];
		contextManage->cc->modelViewMatrix[5]=matrix[5];
		contextManage->cc->modelViewMatrix[6]=matrix[9];
		contextManage->cc->modelViewMatrix[7]=matrix[13];
		contextManage->cc->modelViewMatrix[8]=matrix[2];
		contextManage->cc->modelViewMatrix[9]=matrix[6];
		contextManage->cc->modelViewMatrix[10]=matrix[10];
		contextManage->cc->modelViewMatrix[11]=matrix[14];
		contextManage->cc->modelViewMatrix[12]=matrix[3];
		contextManage->cc->modelViewMatrix[13]=matrix[7];
		contextManage->cc->modelViewMatrix[14]=matrix[11];
		contextManage->cc->modelViewMatrix[15]=matrix[15];
	}

	if(contextManage->cc->matrixMode == SGL_PROJECTION){
	
		contextManage->cc->projectionMatrix[0]=matrix[0];
		contextManage->cc->projectionMatrix[1]=matrix[4];
		contextManage->cc->projectionMatrix[2]=matrix[8];
		contextManage->cc->projectionMatrix[3]=matrix[12];
		contextManage->cc->projectionMatrix[4]=matrix[1];
		contextManage->cc->projectionMatrix[5]=matrix[5];
		contextManage->cc->projectionMatrix[6]=matrix[9];
		contextManage->cc->projectionMatrix[7]=matrix[13];
		contextManage->cc->projectionMatrix[8]=matrix[2];
		contextManage->cc->projectionMatrix[9]=matrix[6];
		contextManage->cc->projectionMatrix[10]=matrix[10];
		contextManage->cc->projectionMatrix[11]=matrix[14];
		contextManage->cc->projectionMatrix[12]=matrix[3];
		contextManage->cc->projectionMatrix[13]=matrix[7];
		contextManage->cc->projectionMatrix[14]=matrix[11];
		contextManage->cc->projectionMatrix[15]=matrix[15];
	}
}

//mult matrix with actual
void sglMyMultMatrix(const float *matrix) {

	if(contextManage->contextCount == 0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}
	 
	float *arrHelp = new float[16];

	if(contextManage->cc->matrixMode == SGL_MODELVIEW){

		arrHelp[0] = matrix[0]*contextManage->cc->modelViewMatrix[0] + matrix[4]*contextManage->cc->modelViewMatrix[1] + 
			+ matrix[8]*contextManage->cc->modelViewMatrix[2] + matrix[12]*contextManage->cc->modelViewMatrix[3];
		arrHelp[1] = matrix[1]*contextManage->cc->modelViewMatrix[0] + matrix[5]*contextManage->cc->modelViewMatrix[1] + 
			+ matrix[9]*contextManage->cc->modelViewMatrix[2] + matrix[13]*contextManage->cc->modelViewMatrix[3];
		arrHelp[2] = matrix[2]*contextManage->cc->modelViewMatrix[0] + matrix[6]*contextManage->cc->modelViewMatrix[1] + 
			+ matrix[10]*contextManage->cc->modelViewMatrix[2] + matrix[14]*contextManage->cc->modelViewMatrix[3];
		arrHelp[3] = matrix[3]*contextManage->cc->modelViewMatrix[0] + matrix[7]*contextManage->cc->modelViewMatrix[1] + 
			+ matrix[11]*contextManage->cc->modelViewMatrix[2] + matrix[15]*contextManage->cc->modelViewMatrix[3];

		arrHelp[4] = matrix[0]*contextManage->cc->modelViewMatrix[4] + matrix[4]*contextManage->cc->modelViewMatrix[5] + 
			+ matrix[8]*contextManage->cc->modelViewMatrix[6] + matrix[12]*contextManage->cc->modelViewMatrix[7];
		arrHelp[5] = matrix[1]*contextManage->cc->modelViewMatrix[4] + matrix[5]*contextManage->cc->modelViewMatrix[5] + 
			+ matrix[9]*contextManage->cc->modelViewMatrix[6] + matrix[13]*contextManage->cc->modelViewMatrix[7];
		arrHelp[6] = matrix[2]*contextManage->cc->modelViewMatrix[4] + matrix[6]*contextManage->cc->modelViewMatrix[5] + 
			+ matrix[10]*contextManage->cc->modelViewMatrix[6] + matrix[14]*contextManage->cc->modelViewMatrix[7];
		arrHelp[7] = matrix[3]*contextManage->cc->modelViewMatrix[4] + matrix[7]*contextManage->cc->modelViewMatrix[5] + 
			+ matrix[11]*contextManage->cc->modelViewMatrix[6] + matrix[15]*contextManage->cc->modelViewMatrix[7];

		arrHelp[8] = matrix[0]*contextManage->cc->modelViewMatrix[8] + matrix[4]*contextManage->cc->modelViewMatrix[9] + 
			+ matrix[8]*contextManage->cc->modelViewMatrix[10] + matrix[12]*contextManage->cc->modelViewMatrix[11];
		arrHelp[9] = matrix[1]*contextManage->cc->modelViewMatrix[8] + matrix[5]*contextManage->cc->modelViewMatrix[9] + 
			+ matrix[9]*contextManage->cc->modelViewMatrix[10] + matrix[13]*contextManage->cc->modelViewMatrix[11];
		arrHelp[10] = matrix[2]*contextManage->cc->modelViewMatrix[8] + matrix[6]*contextManage->cc->modelViewMatrix[9] + 
			+ matrix[10]*contextManage->cc->modelViewMatrix[10] + matrix[14]*contextManage->cc->modelViewMatrix[11];
		arrHelp[11] = matrix[3]*contextManage->cc->modelViewMatrix[8] + matrix[7]*contextManage->cc->modelViewMatrix[9] + 
			+ matrix[11]*contextManage->cc->modelViewMatrix[10] + matrix[15]*contextManage->cc->modelViewMatrix[11];

		arrHelp[12] = matrix[0]*contextManage->cc->modelViewMatrix[12] + matrix[4]*contextManage->cc->modelViewMatrix[13] + 
			+ matrix[8]*contextManage->cc->modelViewMatrix[14] + matrix[12]*contextManage->cc->modelViewMatrix[15];
		arrHelp[13] = matrix[1]*contextManage->cc->modelViewMatrix[12] + matrix[5]*contextManage->cc->modelViewMatrix[13] + 
			+ matrix[9]*contextManage->cc->modelViewMatrix[14] + matrix[13]*contextManage->cc->modelViewMatrix[15];
		arrHelp[14] = matrix[2]*contextManage->cc->modelViewMatrix[12] + matrix[6]*contextManage->cc->modelViewMatrix[13] + 
			+ matrix[10]*contextManage->cc->modelViewMatrix[14] + matrix[14]*contextManage->cc->modelViewMatrix[15];
		arrHelp[15] = matrix[3]*contextManage->cc->modelViewMatrix[12] + matrix[7]*contextManage->cc->modelViewMatrix[13] + 
			+ matrix[11]*contextManage->cc->modelViewMatrix[14] + matrix[15]*contextManage->cc->modelViewMatrix[15];


	
		for(int i=0; i < 16;i++){
		
			contextManage->cc->modelViewMatrix[i] = arrHelp[i];
		}
	}

	if(contextManage->cc->matrixMode == SGL_PROJECTION){
		
		arrHelp[0] = matrix[0]*contextManage->cc->projectionMatrix[0] + matrix[4]*contextManage->cc->projectionMatrix[1] + 
			+ matrix[8]*contextManage->cc->projectionMatrix[2] + matrix[12]*contextManage->cc->projectionMatrix[3];
		arrHelp[1] = matrix[1]*contextManage->cc->projectionMatrix[0] + matrix[5]*contextManage->cc->projectionMatrix[1] + 
			+ matrix[9]*contextManage->cc->projectionMatrix[2] + matrix[13]*contextManage->cc->projectionMatrix[3];
		arrHelp[2] = matrix[2]*contextManage->cc->projectionMatrix[0] + matrix[6]*contextManage->cc->projectionMatrix[1] + 
			+ matrix[10]*contextManage->cc->projectionMatrix[2] + matrix[14]*contextManage->cc->projectionMatrix[3];
		arrHelp[3] = matrix[3]*contextManage->cc->projectionMatrix[0] + matrix[7]*contextManage->cc->projectionMatrix[1] + 
			+ matrix[11]*contextManage->cc->projectionMatrix[2] + matrix[15]*contextManage->cc->projectionMatrix[3];

		arrHelp[4] = matrix[0]*contextManage->cc->projectionMatrix[4] + matrix[4]*contextManage->cc->projectionMatrix[5] + 
			+ matrix[8]*contextManage->cc->projectionMatrix[6] + matrix[12]*contextManage->cc->projectionMatrix[7];
		arrHelp[5] = matrix[1]*contextManage->cc->projectionMatrix[4] + matrix[5]*contextManage->cc->projectionMatrix[5] + 
			+ matrix[9]*contextManage->cc->projectionMatrix[6] + matrix[13]*contextManage->cc->projectionMatrix[7];
		arrHelp[6] = matrix[2]*contextManage->cc->projectionMatrix[4] + matrix[6]*contextManage->cc->projectionMatrix[5] + 
			+ matrix[10]*contextManage->cc->projectionMatrix[6] + matrix[14]*contextManage->cc->projectionMatrix[7];
		arrHelp[7] = matrix[3]*contextManage->cc->projectionMatrix[4] + matrix[7]*contextManage->cc->projectionMatrix[5] + 
			+ matrix[11]*contextManage->cc->projectionMatrix[6] + matrix[15]*contextManage->cc->projectionMatrix[7];

		arrHelp[8] = matrix[0]*contextManage->cc->projectionMatrix[8] + matrix[4]*contextManage->cc->projectionMatrix[9] + 
			+ matrix[8]*contextManage->cc->projectionMatrix[10] + matrix[12]*contextManage->cc->projectionMatrix[11];
		arrHelp[9] = matrix[1]*contextManage->cc->projectionMatrix[8] + matrix[5]*contextManage->cc->projectionMatrix[9] + 
			+ matrix[9]*contextManage->cc->projectionMatrix[10] + matrix[13]*contextManage->cc->projectionMatrix[11];
		arrHelp[10] = matrix[2]*contextManage->cc->projectionMatrix[8] + matrix[6]*contextManage->cc->projectionMatrix[9] + 
			+ matrix[10]*contextManage->cc->projectionMatrix[10] + matrix[14]*contextManage->cc->projectionMatrix[11];
		arrHelp[11] = matrix[3]*contextManage->cc->projectionMatrix[8] + matrix[7]*contextManage->cc->projectionMatrix[9] + 
			+ matrix[11]*contextManage->cc->projectionMatrix[10] + matrix[15]*contextManage->cc->projectionMatrix[11];

		arrHelp[12] = matrix[0]*contextManage->cc->projectionMatrix[12] + matrix[4]*contextManage->cc->projectionMatrix[13] + 
			+ matrix[8]*contextManage->cc->projectionMatrix[14] + matrix[12]*contextManage->cc->projectionMatrix[15];
		arrHelp[13] = matrix[1]*contextManage->cc->projectionMatrix[12] + matrix[5]*contextManage->cc->projectionMatrix[13] + 
			+ matrix[9]*contextManage->cc->projectionMatrix[14] + matrix[13]*contextManage->cc->projectionMatrix[15];
		arrHelp[14] = matrix[2]*contextManage->cc->projectionMatrix[12] + matrix[6]*contextManage->cc->projectionMatrix[13] + 
			+ matrix[10]*contextManage->cc->projectionMatrix[14] + matrix[14]*contextManage->cc->projectionMatrix[15];
		arrHelp[15] = matrix[3]*contextManage->cc->projectionMatrix[12] + matrix[7]*contextManage->cc->projectionMatrix[13] + 
			+ matrix[11]*contextManage->cc->projectionMatrix[14] + matrix[15]*contextManage->cc->projectionMatrix[15];

	
		for(int i=0; i < 16;i++){
		
			contextManage->cc->projectionMatrix[i] = arrHelp[i];
		}
	}

	//delete arrHelp;

}

//mult matrix with actual
void sglMultMatrix(const float *matrix) {

	if(contextManage->contextCount == 0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	float arrHelp2[16];
	arrHelp2[0] = matrix[0];
	arrHelp2[1] = matrix[4]; 
	arrHelp2[2] = matrix[8]; 
	arrHelp2[3] = matrix[12]; 
	arrHelp2[4] = matrix[1]; 
	arrHelp2[5] = matrix[5]; 
	arrHelp2[6] = matrix[9]; 
	arrHelp2[7] = matrix[13]; 
	arrHelp2[8] = matrix[2]; 
	arrHelp2[9] = matrix[6]; 
	arrHelp2[10] = matrix[10]; 
	arrHelp2[11] = matrix[14]; 
	arrHelp2[12] = matrix[3]; 
	arrHelp2[13] = matrix[7]; 
	arrHelp2[14] = matrix[11]; 
	arrHelp2[15] = matrix[15]; 
	
	sglMyMultMatrix(arrHelp2);
	
}

//set transform matrix and mult with actual - right column is changed
void sglTranslate(float x, float y, float z) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	contextManage->cc->clearTransformMatrix();

	contextManage->cc->transformMatrix[3] = x;
	contextManage->cc->transformMatrix[7] = y;
	contextManage->cc->transformMatrix[11] = z;
		
	sglMyMultMatrix(contextManage->cc->transformMatrix);
}
///set transform matrix and mult with actual - diagonal is changed
void sglScale(float scalex, float scaley, float scalez) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	contextManage->cc->clearTransformMatrix();

	contextManage->cc->transformMatrix[0] = scalex;
	contextManage->cc->transformMatrix[5] = scaley;
	contextManage->cc->transformMatrix[10] = scalez;
	
	sglMyMultMatrix(contextManage->cc->transformMatrix);

		
}
//set transform matrix and mult with actual
//the same thing as translate to origin, rotateY and translate back
void sglRotate2D(float angle, float centerx, float centery) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	sglTranslate(centerx,centery,0);

	contextManage->cc->clearTransformMatrix(); 
	contextManage->cc->transformMatrix[0] = cos(angle);
    contextManage->cc->transformMatrix[1] = -sin(angle);
    contextManage->cc->transformMatrix[4] = sin(angle);
    contextManage->cc->transformMatrix[5] = cos(angle);
	sglMyMultMatrix(contextManage->cc->transformMatrix);

	sglTranslate(-centerx,-centery,0);
}
//set transform matrix and mult with actual
void sglRotateY(float angle) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	contextManage->cc->clearTransformMatrix(); 

	contextManage->cc->transformMatrix[0] = cos(angle);
	contextManage->cc->transformMatrix[2] = -sin(angle);
    contextManage->cc->transformMatrix[8] = sin(angle);
    contextManage->cc->transformMatrix[10] = cos(angle);
	
	sglMyMultMatrix(contextManage->cc->transformMatrix);
}
//set ortho projection and mult with projection
void sglOrtho(float left, float right, float bottom, float top, float near, float far) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	float width = right-left;
        float height = top-bottom;
        float depth = far-near;
        
        float tx=-(right+left)/width;
        float ty=-(top+bottom)/height;
        float tz=-(far+near)/depth;

        float ortho[16] = {
                2/width,0,0,tx,
                0,2/height,0,ty,
                0,0,-2/(far-near),tz,
                0,0,0,1
        };

	
	sglMyMultMatrix(ortho);
	
	
}
//set frustrum matrix and mult with projection
void sglFrustum(float left, float right, float bottom, float top, float near, float far) {

	if(contextManage->contextCount == 0){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(near<=0 || far<=0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}
	
	float frustrum[16] = {
		2*near/(right-left),0,(right+left)/(right-left),0,
		0,2*near/(top-bottom),(top+bottom)/(top-bottom),0,
		0,0,-(far+near)/(far-near),-2*far*near/(far-near),
		0,0,-1,0
	};
	sglMyMultMatrix(frustrum);

}

//set variables of viewport
void sglViewport(int x, int y, int width, int height) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(width<=0 || height <=0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}
	contextManage->cc->viewportX = x;
	contextManage->cc->viewportY = y;
	contextManage->cc->viewportHeight = height;
	contextManage->cc->viewportWidth = width;

}

//---------------------------------------------------------------------------
// Attribute functions
//---------------------------------------------------------------------------
//set color
void sglColor3f(float r, float g, float b) {
	
	contextManage->cc->currentColor.r = r;
	contextManage->cc->currentColor.g = g;
	contextManage->cc->currentColor.b = b;
}

// if draw lines or fill primitives
void sglAreaMode(sglEAreaMode mode) {
	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}
	if(mode == SGL_POINT || mode == SGL_LINE || mode == SGL_FILL){

		contextManage->cc->areaMode = mode;
	}
	else{
		setErrCode(SGL_INVALID_ENUM);
		return;
	}
}

//set point size
void sglPointSize(float size) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(size<=0){
	
		setErrCode(SGL_INVALID_VALUE);
		return;
	}
	contextManage->cc->pointSize = size;
}

//turn on depth test
void sglEnable(sglEEnableFlags cap) {

	if(contextManage->contextCount == 0 || contextManage->cc->drawing == true){
	
		setErrCode(SGL_INVALID_OPERATION);
		return;
	}

	if(cap == SGL_DEPTH_TEST){
	
		contextManage->cc->depth_test = true;
		sglClear(SGL_COLOR_BUFFER_BIT);
		sglClear(SGL_DEPTH_BUFFER_BIT);
	}
	else{
	
		setErrCode(SGL_INVALID_ENUM);
		return;
	}
}

// turn off depth test
void sglDisable(sglEEnableFlags cap) {

	if(cap == SGL_DEPTH_TEST){
	
		contextManage->cc->depth_test = false;
	}
}

//---------------------------------------------------------------------------
// RayTracing oriented functions
//---------------------------------------------------------------------------

//only set parameter to true
//hotovo
void sglBeginScene() {

	contextManage->cc->sceneDefiniton = true;
	contextManage->cc->drawing = true;
}


// end of sceneDefinition in current context
void sglEndScene() {

	contextManage->cc->sceneDefiniton = false;
	contextManage->cc->drawing = true;
}

//add sphere to primitiveBuffer in current context
void sglSphere(const float x,
			   const float y,
			   const float z,
			   const float radius) {
				  // printf("%f %f %f %f \n", x,y,z,radius);
				  contextManage->cc->addSphere(x,y,z,radius);
}

// only set parameters to current material
//hotovo
void sglMaterial(const float r,
				 const float g,
				 const float b,
				 const float kd,
				 const float ks,
				 const float shine,
				 const float T,
				 const float ior) {

					 contextManage->cc->currentMaterial.r = r;
					 contextManage->cc->currentMaterial.g = g;
					 contextManage->cc->currentMaterial.b = b;
					 contextManage->cc->currentMaterial.kd = kd;
					 contextManage->cc->currentMaterial.ks = ks;
					 contextManage->cc->currentMaterial.shine = shine;
					 contextManage->cc->currentMaterial.T = T;
					 contextManage->cc->currentMaterial.ior = ior;
}

//add light to lightBuffer in current context
void sglPointLight(const float x,
				   const float y,
				   const float z,
				   const float r,
				   const float g,
				   const float b) {


					   contextManage->cc->addLight(x,y,z,r,g,b);
}

void sglRayTraceScene() {

	contextManage->cc->raytraceScene();
}

void sglRasterizeScene() {}

void sglEnvironmentMap(const int width,
					   const int height,
					   float *texels)
{

	contextManage->cc->envMapWidth = width;
	contextManage->cc->envMapHeight = height;
	contextManage->cc->enviromentMap = new MyColor[height*width];
	for (int i = 0; i < (height*width); i++) {
//		printf("added %i colors", i);
		contextManage->cc->enviromentMap[i].r = texels[3*i];
		contextManage->cc->enviromentMap[i].g = texels[3*i + 1];
		contextManage->cc->enviromentMap[i].b = texels[3*i + 2];
	}

}

void sglEmissiveMaterial(
						 const float r,
						 const float g,
						 const float b,
						 const float c0,
						 const float c1,
						 const float c2
						 )
{

	contextManage->cc->currentEMaterial = MyEmissiveMaterial(r,g,b,c0,c1,c2);
	contextManage->cc->isEmissive = true;
}

